#include"my.h"
sqlite3* db = NULL;

//退出功能 
void dealExit(int newconfd,MSG *pm)
{
	//封包 
	strcpy(pm->data,"退出成功");

	//回发
	if(write(newconfd,pm,sizeof(MSG))<0)
	{
		perror("write");
		return;
	}
}


//注册功能 
void dealRegister(int newconfd,MSG *pm)
{

	//1.用户信息表查找是否存在该用户名 pm->name

	char sql[100]="\0";
	//2.拼接
	sprintf(sql,"select *from usrInfo where name='%s';",pm->name);

	char **result=NULL;
	int row,col;
	//3.查询 
	if(sqlite3_get_table(db,sql,&result,&row,&col,NULL))
	{
		printf("%s\n",sqlite3_errmsg(db));
		sqlite3_close(db);
		return;
	}

	//判断是否找到
	if(row)
	{
		//1).能找到 回复客户端 注册失败 
		strcpy(pm->data,"注册失败,用户已存在!");

	}
	else 
	{
		//2）没找到 将用户名 密码插入用户信息表 回复 注册成功

		//注册 
		memset(sql,0,sizeof(sql));
		sprintf(sql,"insert into usrInfo values('%s',%s);",pm->name,pm->data);

		//执行插入操作
		if(sqlite3_exec(db,sql,NULL,NULL,NULL))
		{
			printf("%s\n",sqlite3_errmsg(db));
			sqlite3_close(db);
			return;

		}
		strcpy(pm->data,"注册成功");
	}

	//将数据包回发客户端 
	if(write(newconfd,pm,sizeof(MSG))<0)
	{
		perror("write");
		return;
	}

	//释放结果集空间
	sqlite3_free_table(result);
}


//处理登录功能
void dealLogin(int newconfd,MSG *pm)
{
	char sql[100]="\0";
	//2.拼接
	sprintf(sql,"select *from usrInfo where name='%s' and password=%s;",pm->name,pm->data);

	char **result=NULL;
	int row,col;
	//3.查询 
	if(sqlite3_get_table(db,sql,&result,&row,&col,NULL))
	{
		printf("%s\n",sqlite3_errmsg(db));
		sqlite3_close(db);
		return;
	}

	//判断是否有结果
	if(row)//说明用户名 密码都正确
	{
		//回发登录成功
		strcpy(pm->data,"登录成功");
	}
	else 
	{
		//回发登录失败
		strcpy(pm->data,"登录失败");
	}
	//将数据包回发客户端 
	if(write(newconfd,pm,sizeof(MSG))<0)
	{
		perror("write");
		return;
	}	
}

//详细查询单词过程  行参：要查询的单词
int searchWord(char *word)
{
	char line[300]="\0";//存储读到一行数据
	int ret,len = strlen(word);
	//打开文件
	FILE *fp = fopen("dict.txt","r");
	if(NULL==fp)
	{
		perror("fopen");
		return;
	}

	//循环读取一行匹配
	while(1)
	{
		//读取文件一行
		if(!fgets(line,sizeof(line),fp))
		{
			break;
		}

		//匹配
		ret = strncmp(word,line,len);
		if(ret>0)
		{
			continue;
		}
		else if(ret<0||line[len]!=' ')
		{
			return 0;
		}
		else 
		{
			strcpy(word,line);
			return 1;
		}
	}

	//说明没找到
	return 0;
	
}

//查询单词
void dealQuery(int newconfd,MSG *pm)//pm->data word
{
	char sql[100]="\0";

	//记录 查询的单词
	char word[50]="\0";
	char *ptime = NULL;
	time_t t;

	//记录 
	strcpy(word,pm->data);

	//查询单词 
	 int ret = searchWord(pm->data);//ret 为1 说明查到   0 说明没查到

	//是否查到单词
	if(ret)
	{
		//1.将数据插入历史记录表 --》背词本
		//获取当前系统时间 是整型
		t = time(NULL);

		//将整型时间转为字符串格式时间
		ptime = ctime(&t);
		
		//abc\n\0
		ptime[strlen(ptime)-1] = '\0';
		//如果查到单词--》1)将单词插入背词本  2)回发解释
		sprintf(sql,"insert into historyInfo values('%s','%s','%s');",word,pm->name,ptime);
		
		//执行插入操作
		if(sqlite3_exec(db,sql,NULL,NULL,NULL))
		{
			printf("%s\n",sqlite3_errmsg(db));
			sqlite3_close(db);
			return;
		}
	}
	else 
	{
		//如果没查到-->回发单词不存在
		strcpy(pm->data,"单词不存在");
	}

	//回发客户端 
	if(write(newconfd,pm,sizeof(MSG))<0)
	{
		perror("write");
	}	

}

//处理背词本功能 
void dealHistory(int newconfd,MSG *pm)
{
	char sql[100]="\0";
	//2.拼接
	sprintf(sql,"select *from historyInfo where name='%s';",pm->name);

	char **result=NULL;
	int row,col;
	//3.查询 
	if(sqlite3_get_table(db,sql,&result,&row,&col,NULL))
	{
		printf("%s\n",sqlite3_errmsg(db));
		sqlite3_close(db);
		return;
	}

	int i;
	//判断是否有结果
	if(row)
	{
		//循环回发结果
		for(i=0;i<(row+1)*col;i++)
		{
			strcpy(pm->data,result[i]);

			//将记录回发
			if(write(newconfd,pm,sizeof(MSG))<0)
			{
				perror("write");
				return;
			}	

			usleep(3);//微妙为单位 避免粘包
			memset(pm->data,0,sizeof(pm->data));
		}

		strcpy(pm->data,"sendOver");
		//发送客户端结束标记
		if(write(newconfd,pm,sizeof(MSG))<0)
		{
			perror("write");
			return;
		}	
	}
}
//线程处理函数
void *dealClient(void *p)
{
	pthread_detach(pthread_self());//参数：当前调用线程tid

	//获取参数
	int newconfd = *(int*)p;

	MSG m;
	//具体功能处理
	while(1)
	{
		//读取客户端数据包
		if(read(newconfd,&m,sizeof(m))<=0)//<0 出错 ==0 对方下线
		{
			break;
		}

		//解析数据包
		switch(m.type)
		{
		case E:
			dealExit(newconfd,&m);
			break;
		case R:
			dealRegister(newconfd,&m);
			break;
		case L:
			dealLogin(newconfd,&m);
			break;
		case Q:
			dealQuery(newconfd,&m);
			break;
		case H:
			dealHistory(newconfd,&m);
			break;
		default:
			puts("匹配错误");
			break;
		}
	}

	printf("客户端%d下线\n",newconfd);
}

int main(int argc,char*argv[])
{
	if(argc!=3)
	{
		printf("%s 本机ip  本机端口\n",argv[0]);
		exit(-1);
	}

	//1.做准备工作
	//1)创建数据库
	//2)创建两个表（用户信息表 历史记录表）
	if(sqlite3_open("usr.db",&db))
	{
		printf("open db:%s\n",sqlite3_errmsg(db));
		exit(-1);
	}

	char *sql="create table if not exists usrInfo(name varchar(20),password integer)";
	if(sqlite3_exec(db,sql,NULL,NULL,NULL))
	{
		printf("exec create table usrInfo:%s\n",sqlite3_errmsg(db));
		exit(-1);
	}

	sql="create table if not exists historyInfo(word varchar(20),name varchar(20),time varchar(20))";
	if(sqlite3_exec(db,sql,NULL,NULL,NULL))
	{
		printf("exec create table historyInfo:%s\n",sqlite3_errmsg(db));
		exit(-1);
	}


	//2.实现多线程并发服务器
	//1.创建套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		perror("socket");
		exit(-1);
	}


	//2.绑定 套接字+本机地址信息(ip+端口+协议族)
	//填充地址信息
	struct sockaddr_in myselfaddr;
	myselfaddr.sin_family = AF_INET;   //协议族 就是ip版本
	myselfaddr.sin_port = htons(atoi(argv[2]));//本机端口号 必须为网络格式
	myselfaddr.sin_addr.s_addr = inet_addr(argv[1]); //本机ip 网络格式
	int ret = bind(sfd,(struct sockaddr*)&myselfaddr,sizeof(myselfaddr));
	if(ret<0)
	{
		perror("bind");
		close(sfd);
		exit(-1);
	}

	//3.监听(设置最大并发量)
	int ret1 = listen(sfd,10);
	if(ret1<0)
	{
		perror("listen");
		close(sfd);
		exit(-1);
	}

	pthread_t id;

	while(1)
	{
		//3.取得连接
		int newconfd = accept(sfd,NULL,NULL);//成功返回 标志3次握手完成
		if(newconfd<0)
		{
			perror("accept");
			close(sfd);
			exit(-1);
		}

		//4.创建子线程处理客户端请求
		pthread_create(&id,NULL,dealClient,&newconfd);//NULL 线程为结合态 子线程消亡 需要主线程收尸

	}
}
